package com.freeter.modules.gjs.service.impl;

import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.mapper.Wrapper;
import com.freeter.modules.gjs.entity.DamageReport;
import com.freeter.modules.gjs.mapper.DamageReportMapper;
import com.freeter.modules.gjs.service.DamageReportService;
import com.freeter.modules.gjs.entity.AppRequestRecord;
import com.freeter.modules.gjs.mapper.AppRequestRecordMapper;
import com.freeter.modules.gjs.entity.StockStatus;
import com.freeter.modules.gjs.mapper.StockStatusMapper;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.transaction.annotation.Transactional;
import java.util.Base64;
import java.io.File;
import java.io.FileOutputStream;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Map;
import java.util.List;
import java.util.ArrayList;
import java.util.UUID;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class DamageReportServiceImpl implements DamageReportService {
    @Autowired
    private DamageReportMapper damageReportMapper;
    @Autowired private AppRequestRecordMapper appRequestRecordMapper;
    @Autowired private StockStatusMapper stockStatusMapper;
    @Value("${dmg.img.folder:/tmp/damage_report}")
    private String dmgImgFolder;
    @Value("${calc.ticket.folder:/tmp/calc_ticket}")
    private String calcTicketFolder;

    private String randomFileName() {
        java.util.Calendar currentDate = java.util.Calendar.getInstance();
        int YYYY = currentDate.get(java.util.Calendar.YEAR);
        int MO = currentDate.get(java.util.Calendar.MONTH) + 1;
        int DD = currentDate.get(java.util.Calendar.DATE);
        int hh = currentDate.get(java.util.Calendar.HOUR_OF_DAY);
        int mm = currentDate.get(java.util.Calendar.MINUTE);
        int ss = currentDate.get(java.util.Calendar.SECOND);
        int fff = currentDate.get(java.util.Calendar.MILLISECOND);
        int randomNum = (int)(Math.random() * (999 - 100 + 1) + 100);
        return String.format("%04d%02d%02d%02d%02d%02d%03d%d", YYYY, MO, DD, hh, mm, ss, fff, randomNum);
    }

    @Override
    public List<DamageReport> getAllDamageReports() {
        Wrapper<DamageReport> wrapper = new EntityWrapper<>();
        wrapper.eq("is_deleted", 0);
        return damageReportMapper.selectList(wrapper);
    }

    @Override
    public DamageReport getDamageReportById(Long id) {
        Wrapper<DamageReport> wrapper = new EntityWrapper<>();
        wrapper.eq("id", id).eq("is_deleted", 0);
        List<DamageReport> list = damageReportMapper.selectList(wrapper);
        return list.isEmpty() ? null : list.get(0);
    }

    @Override
    public DamageReport getDamageReportByReportNo(String reportNo) {
        Wrapper<DamageReport> wrapper = new EntityWrapper<>();
        wrapper.eq("report_no", reportNo).eq("is_deleted", 0);
        List<DamageReport> list = damageReportMapper.selectList(wrapper);
        return list.isEmpty() ? null : list.get(0);
    }

    @Override
    public List<DamageReport> getDamageReportsByUserId(Long userId) {
        Wrapper<DamageReport> wrapper = new EntityWrapper<>();
        wrapper.eq("user_id", userId).eq("is_deleted", 0);
        return damageReportMapper.selectList(wrapper);
    }

    @Override
    public List<DamageReport> getDamageReportsByItemCode(String itemCode) {
        Wrapper<DamageReport> wrapper = new EntityWrapper<>();
        wrapper.eq("item_code", itemCode).eq("is_deleted", 0);
        return damageReportMapper.selectList(wrapper);
    }

    @Override
    public List<DamageReport> getDamageReportsBySiteCode(String siteCode) {
        Wrapper<DamageReport> wrapper = new EntityWrapper<>();
        wrapper.eq("site_code", siteCode).eq("is_deleted", 0);
        return damageReportMapper.selectList(wrapper);
    }

    @Override
    public List<DamageReport> getDamageReportsByStatus(String status) {
        Wrapper<DamageReport> wrapper = new EntityWrapper<>();
        wrapper.eq("status", status).eq("is_deleted", 0);
        return damageReportMapper.selectList(wrapper);
    }

    @Override
    public List<DamageReport> getDamageReportsByDamageType(String damageType) {
        Wrapper<DamageReport> wrapper = new EntityWrapper<>();
        wrapper.eq("damage_type", damageType).eq("is_deleted", 0);
        return damageReportMapper.selectList(wrapper);
    }

    @Override
    public DamageReport createDamageReport(DamageReport damageReport) {
        damageReportMapper.insert(damageReport);
        return damageReport;
    }

    @Override
    public DamageReport updateDamageReport(Long id, DamageReport damageReport) {
        damageReport.setId(id);
        damageReportMapper.updateById(damageReport);
        return damageReport;
    }

    @Override
    public boolean deleteDamageReport(Long id) {
        return damageReportMapper.deleteById(id) > 0;
    }

    @Override
    public boolean deleteDamageReportByReportNo(String reportNo) {
        Wrapper<DamageReport> wrapper = new EntityWrapper<>();
        wrapper.eq("report_no", reportNo);
        return damageReportMapper.delete(wrapper) > 0;
    }

    @Override
    public List<DamageReport> getDamageReportsByCondition(String name, Integer state) {
        Wrapper<DamageReport> wrapper = new EntityWrapper<>();
        if (name != null) wrapper.eq("name", name);
        if (state != null) wrapper.eq("state", state);
        wrapper.eq("is_deleted", 0);
        return damageReportMapper.selectList(wrapper);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean reportDemage(Map<String, Object> req) throws Exception {
        // 1. 参数提取
        String projectCode = (String) req.get("project_code");
        String siteId = String.valueOf(req.get("site_id"));
        String id = String.valueOf(req.get("id"));
        Double qty = req.get("qty") == null ? null : Double.valueOf(req.get("qty").toString());
        String remarks = (String) req.get("remarks");
        List<String> photos = (List<String>) req.getOrDefault("photos", new ArrayList<>());
        List<String> videos = (List<String>) req.getOrDefault("videos", new ArrayList<>());
        String requestId = (String) req.get("request_id");
        Long userId = req.get("user_id") == null ? null : Long.valueOf(req.get("user_id").toString());
        String csrfToken = (String) req.get("csrf_token");
        // 2. 幂等校验
        if (requestId != null && userId != null && csrfToken != null) {
            AppRequestRecord exist = appRequestRecordMapper.selectOne(new AppRequestRecord() {{
                setUserId(userId); setCsrfToken(csrfToken); setRequestId(requestId); setActionType("report-demage");
            }});
            if (exist != null) return true;
        }
        // 3. 参数校验
        if (projectCode == null || siteId == null || id == null || qty == null) {
            throw new Exception("Missing required field");
        }
        if (qty <= 0) throw new Exception("Please input valid QTY");
        // 4. 查询库存
        StockStatus stock = stockStatusMapper.selectById(Long.valueOf(id));
        if (stock == null) throw new Exception("Item not found");
        // 5. 写入damage_report
        DamageReport dr = new DamageReport();
        dr.setItemCode(stock.getItemBarcode());
        dr.setSiteCode(siteId);
        dr.setUserId(userId);
        dr.setQuantity(new java.math.BigDecimal(qty));
        dr.setRemarks(remarks);
        dr.setStatus("Pending");
        dr.setCreatedAt(java.time.LocalDateTime.now());
        damageReportMapper.insert(dr);
        // 6. 更新hold_qty
        double holdQty = stock.getHoldQty() == null ? 0 : stock.getHoldQty();
        stock.setHoldQty(holdQty + qty);
        stockStatusMapper.updateById(stock);
        // 7. 写入app_request_record
        if (requestId != null && userId != null && csrfToken != null) {
            AppRequestRecord record = new AppRequestRecord();
            record.setUserId(userId);
            record.setCsrfToken(csrfToken);
            record.setRequestId(requestId);
            record.setActionType("report-demage");
            record.setRecordTime(new java.util.Date());
            appRequestRecordMapper.insert(record);
        }
        // 8. 图片/视频保存
        String dirPath = dmgImgFolder + File.separator + projectCode + File.separator + dr.getId();
        File dir = new File(dirPath);
        if (!dir.exists()) dir.mkdirs();
        for (String photo : photos) {
            if (photo != null && !photo.isEmpty()) {
                String filename = randomFileName() + ".jpg";
                File file = new File(dirPath, filename);
                byte[] buffer = Base64.getDecoder().decode(photo);
                try (FileOutputStream fos = new FileOutputStream(file)) {
                    fos.write(buffer);
                }
            }
        }
        for (String video : videos) {
            if (video != null && !video.isEmpty()) {
                String filename = randomFileName() + ".mp4";
                File file = new File(dirPath, filename);
                byte[] buffer = Base64.getDecoder().decode(video);
                try (FileOutputStream fos = new FileOutputStream(file)) {
                    fos.write(buffer);
                }
            }
        }
        // 9. 写本地damage_report文件
        java.util.Map<String, Object> writeData = new java.util.HashMap<>();
        writeData.put("id", dr.getId());
        writeData.put("stock_id", id);
        writeData.put("qty", qty);
        writeData.put("remarks", remarks);
        writeData.put("reporter_user_id", userId);
        writeData.put("status", "Pending");
        String damageReportFilePath = calcTicketFolder + File.separator + "damage_report" + File.separator + UUID.randomUUID();
        File file = new File(damageReportFilePath);
        file.getParentFile().mkdirs();
        Files.write(Paths.get(damageReportFilePath), new com.fasterxml.jackson.databind.ObjectMapper().writeValueAsBytes(writeData));
        return true;
    }
} 